// AceAuth.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <memory>
#include <string>
#include <iostream>

#include "AceEnvironment.h"
#include "AceSession.h"

#include "OtpEnvironment.h"
#include "OtpSession.h"

const int ERR_OK            = 0;
const int ERR_INVALID_INPUT = -1;
const int ERR_LOCK_ACCOUNT  = -2;
const int ERR_NEXT_CODE     = -3;
const int ERR_ACCESS_DENIED = -4;
const int ERR_OTHER         = -5;

void showCopyright(void)
{
  std::cout << "ACE/OTP client authentication utility @ " << __DATE__ << std::endl
            << "(C) 1999-2011 NSFOCUS Corporation. All rights Reserved" << std::endl << std::endl;
}

void showHelp(void)
{
  std::cout << "AceAuth [parameters]" << std::endl 
            << std::endl
            << "[Parameters]" << std::endl 
            << std::endl
            << "\t-u<NAME>\taccount name" << std::endl
            << "\t-p<PASS>\tpassword" << std::endl
            << "\t-d\t\tdebug mode" << std::endl
            << "\t-t<MODE>\tauth type (rsa or otp)" << std::endl
            << "\t-c<FILE>\tOTP configuration file" << std::endl
            << "\t-h\t\tshow help" << std::endl
            << std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
  showCopyright();

  if (argc < 2)
  {
    showHelp();

    return ERR_OTHER;
  }

  std::string username, password, authtype, acfpath;
  bool debugMode = false, directReturn = false;
  int ret = ERR_OK;

  for (int i=1; i<argc; i++)
  {
    char *arg = argv[i], *value = arg + 2;

    if ((arg[0] == '-') && (strlen(arg) >= 2))
    {
      switch (arg[1])
      {
      case 'u':
        {
          username = value;
          break;
        }
      case 'p':
        {
          password = value;
          break;
        }
      case 'd':
        {
          debugMode = true;
          break;
        }
      case 'r':
        {
          ret = atoi(value);
          directReturn = true;

          break;
        }
      case 't':
        {
          authtype = value;
          break;
        }
      case 'c':
        {
          acfpath = value;
          break;
        }
      case 'h':
      case '?':
        {
          showHelp();
          return ERR_OTHER;
        }
      default:
        {
          std::cerr << "WARN: unknown parameter - " << arg << std::endl;

          break;
        }
      }
    }
  }

  if (directReturn)
  {
    if (debugMode)
    {
      std::cout << "INFO: direct return " << ret << " for testing." << std::endl;
    }

    return ret;
  }

  if (username.empty() || password.empty())
  {
    std::cerr << "ERROR: account [" << username << "] or password [" << password << "] is empty." << std::endl;

    return ERR_INVALID_INPUT;
  }

  if (debugMode)
  {
    std::cout << "INFO: account " << username << " is begin to login." << std::endl;
  }

  try
  {
    std::auto_ptr<auth::IAuthEnvironment> env;

    if (0 == stricmp(authtype.c_str(), "otp")) 
    {
      if (debugMode)
      {
        std::cout << "INFO: load ACF file from " << acfpath << std::endl;
      }

      env.reset(new otp::COtpEnvironment(acfpath));
    }
    else
    {
      env.reset(new ace::CAceEnvironment());
    }
    
    std::auto_ptr<auth::IAuthSession> session(env->createSession());

    session->open();

    if(!session->lock(username, &ret))
    {
      std::cerr << "ERROR: failed to lock account [" << username << "] for two-step authentication." << std::endl;      

      return ERR_LOCK_ACCOUNT;
    }

    session->check(username, password, &ret);

    switch(ret)
    {
    case ACM_OK:
      {
        if (debugMode)
        {
          std::cout << "INFO: account " << username << " logging is succeeded." << std::endl;
        }

        return ERR_OK;
      }
    case ACM_ACCESS_DENIED:
      {
        if (debugMode)
        {
          std::cout << "INFO: account " << username << " access deined." << std::endl;
        }

        return ERR_ACCESS_DENIED;
      }
    default:
      {
        if (debugMode)
        {
          std::cout << "INFO: account " << username << " logging need try again, retcode = " << ret << std::endl;
        }

        return ERR_OTHER;
      }
    }
  }
  catch(auth::CAuthException& e)
  {
    std::cerr << "ERROR: (" << e.getErrorCode() << "): " << e.getErrorMessage() << std::endl;

    return ERR_OTHER;
  }	
}

